﻿using Red.EngineData.Protocol.Interop;
using Red.EngineData.View;
using System;
using System.Collections.Generic;
using System.Windows.Threading;

namespace Red.EngineData
{
    /// <summary>
    /// Helper class to encapsulate interop expression 'get array size'
    /// </summary>
    public class GetArraySizeExpression
    {
        static public implicit operator Interop( GetArraySizeExpression expression )
        {
            return Interop.Make( "" );
        }
    }

    /// <summary>
    /// /// Helper class to encapsulate interop expression 'get array element'
    /// </summary>
    public class GetArrayElementExpression
    {
        private int _elementIndex;

        public GetArrayElementExpression( int elementIndex )
        {
            _elementIndex = elementIndex;
        }

        static public implicit operator Interop( GetArrayElementExpression expression )
        {
            return Interop.Make( "[" + expression._elementIndex.ToString() + "]" );
        }
    }

    /// <summary>
    /// Helper class which extracts raw data from array
    /// </summary>
    public class ArrayDataEnumerator
    {
        private readonly DataView _array;

        private int _arrayCount;
        private int _arrayIndex;
        private List<String> _arrayValues;

        public delegate void OnEnumerationFailedHandler();
        public delegate void OnEnumerationDoneHandler( List<String> elements );

        public event OnEnumerationFailedHandler OnEnumerationFailed = null;
        public event OnEnumerationDoneHandler OnEnumerationDone = null;

        public ArrayDataEnumerator( DataView array )
        {
            _array = array;
            _arrayCount = -1;
            _arrayIndex = -1;
            _arrayValues = new List<String>();
        }

        public void Start()
        {
            if ( null != _array )
            {
                _arrayCount = -1;
                _arrayIndex = -1;
                _arrayValues.Clear();
                _array.Execute( new GetArraySizeExpression(), OnResponse, OnException );
            }
        }

        void OnResponse( InteropResult result )
        {
            if ( _arrayCount == -1 )
            {
                // we were asking for the node count
                if ( int.TryParse( result.Data, out _arrayCount ) )
                {
                    // ask for first element
                    if ( _arrayCount > 0 )
                    {
                        _arrayIndex = 0;
                        _array.Execute( new GetArrayElementExpression( _arrayIndex ), OnResponse, OnException );
                    }
                }
                else
                {
                    _arrayCount = 0;
                    _arrayIndex = 0;
                    OnEnumerationFailed();
                }
            }
            else if ( _arrayIndex < _arrayCount )
            {
                _arrayValues.Add( result.Data );
                _arrayIndex += 1;

                if ( _arrayIndex == _arrayCount )
                {
                    // report final list
                    OnEnumerationDone( _arrayValues );
                }
                else
                {
                    // get next element
                    _array.Execute( new GetArrayElementExpression( _arrayIndex ), OnResponse, OnException );
                }
            }
        }

        void OnException( ProtocolException ex )
        {
            _arrayCount = 0;
            _arrayIndex = 0;
            OnEnumerationFailed();
        }
    }
}
